package com.neo.tiny.admin.service.auth;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.neo.tiny.admin.dto.user.SysUserDTO;
import com.neo.tiny.admin.entity.sys.*;
import com.neo.tiny.admin.service.sys.*;
import com.neo.tiny.admin.vo.dept.SysDeptVO;
import com.neo.tiny.admin.vo.menu.SysMenuVO;
import com.neo.tiny.admin.vo.post.PostVO;
import com.neo.tiny.admin.vo.role.SysRoleVO;
import com.neo.tiny.common.constant.CacheConstants;
import com.neo.tiny.common.enums.MenuTypeEnum;
import com.neo.tiny.common.util.CommonDoTransfer;
import com.neo.tiny.query.LambdaQueryWrapperBase;
import com.neo.tiny.secrity.model.AdminUserDetails;
import com.neo.tiny.secrity.service.AdminUserDetailsService;
import com.neo.tiny.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author yqz
 * @Description
 * @CreateDate 2022/8/3 18:39
 */
@Slf4j
@Service("userDetailsService")
public class UserDetailsServiceImpl implements AdminUserDetailsService {

    @Autowired
    private SysUserService userService;

    @Autowired
    private SysUserRoleService userRoleService;

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysRoleMenuService roleMenuService;

    @Autowired
    private SysMenuService menuService;

    @Autowired
    private SysUserPostService userPostService;

    @Autowired
    private SysPostService postService;

    @Autowired
    private SysDeptService deptService;

    @Autowired
    private RedisService redisService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        String key = CacheConstants.USER_DETAILS + StrUtil.COLON + username;
        Map<Object, Object> adminUserDetails = redisService.hGetAll(key);
        if (MapUtil.isNotEmpty(adminUserDetails)) {
            return BeanUtil.toBean(adminUserDetails, AdminUserDetails.class);
        }
        AdminUserDetails userDetails = getUserDetails(username);
        // 用户信息默认缓存12小时
        redisService.hSetAll(key, BeanUtil.beanToMap(userDetails), 3600 * 12);
        return userDetails;
    }

    @Override
    public AdminUserDetails getUserDetails(String username) {
        // 查询系统用户 TODO 每次请求都会经过此处，所以后续需要添加缓存
        SysUser user = userService.getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, username));

        Assert.notNull(user, "用户名或密码错误");
        AdminUserDetails userDetails = new AdminUserDetails(BeanUtil.copyProperties(user, SysUserDTO.class));


        // 查询用户角色列表
        List<SysUserRole> roleList = userRoleService.list(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, user.getId()));
        Set<Long> roleIds = roleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());

        if (roleIds.size() > 0) {
            List<SysRole> roles = roleService.list(new LambdaQueryWrapperBase<SysRole>()
                    .in(SysRole::getId, roleIds));
            userDetails.setRoleList(CommonDoTransfer.transfer(roles, SysRoleVO.class));
            // 查询用户拥有的菜单与权限
            List<SysRoleMenu> roleMenuList = roleMenuService.list(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, roleIds));
            if (CollUtil.isNotEmpty(roleMenuList)) {
                Set<Long> menuIds = roleMenuList.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toSet());
                List<SysMenu> menuList = menuService.list(new LambdaQueryWrapper<SysMenu>().in(SysMenu::getId, menuIds));
                if (menuList.size() > 0) {
                    userDetails.setMenuList(CommonDoTransfer.transfer(menuList, SysMenuVO.class));
                    // 获取角色权限
                    Collection<GrantedAuthority> authorities = AuthorityUtils
                            .createAuthorityList(menuList.stream()
                                    .filter(menu -> MenuTypeEnum.BUTTON.getType().equals(menu.getMenuType()))
                                    .map(SysMenu::getPerms).distinct().toArray(String[]::new));
                    userDetails.setAuthorities(authorities);
                }
            }
        }

        // 查询用户拥有的岗位
        List<SysUserPost> userPostList = userPostService.list(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, user.getId()));
        Set<Long> postIds = userPostList.stream().map(SysUserPost::getPostId).collect(Collectors.toSet());
        if (userPostList.size() > 0) {
            List<SysPost> postList = postService.list(new LambdaQueryWrapper<SysPost>().in(SysPost::getId, postIds));
            userDetails.setPostList(CommonDoTransfer.transfer(postList, PostVO.class));
        }
        if (ObjectUtil.isNotEmpty(user.getDeptId())) {
            SysDept dept = deptService.getById(user.getDeptId());
            userDetails.setDept(CommonDoTransfer.transfer(dept, SysDeptVO.class));
        }

        return userDetails;
    }

}
